#ifndef _UDPACCEPTOR_H_
#define _UDPACCEPTOR_H_

#include <netlib/net/p2psocket.h>
#include <netlib/net/socketmanager.h>
#include <utillib/thread/thread.h>

#include <utillib/stl/map.h>
#include <utillib/util/synchronized.h>

#pragma warning (disable: 4786)
#include <set>


namespace netlib
{
	namespace net
	{
		class UDPManager;

		class UDPAcceptor
		{
		public:
			UDPAcceptor( UDPManager *manager );
			virtual ~UDPAcceptor();
			int initialize( WORD port , bool manageMode );

			bool send( netlib::packet::Packet *packet, DWORD ip, WORD port )
			{
				return ( m_listenSocket.send( packet, ip, port ) );
			}
			DWORD run();
			bool existConnectInfo( DWORD ip, WORD port );
		private:
			void localPeerInfo( netlib::packet::Packet *packet );
			void dispatchMessage( netlib::packet::Packet *packet );
			void udpInformationReq( netlib::packet::Packet *packet );
			void serverInfoReq( netlib::packet::Packet *packet );
			void checkNATCondtionReq( netlib::packet::Packet *packet );


			void udpInformation( const char *requestID, const char *searchID );
			UDPSocket m_listenSocket;

			WORD m_listenPort;

			bool m_manageMode;

			UDPManager *m_parentManager;
			utillib::stl::QueueList < netlib::packet::Packet * > m_packetList;

		};
		class UDPManager
		{
		public:
			class UDPAddress : public utillib::util::Synchronized::LockObject
			{
			public:
				UDPAddress() : userID( NULL ){};//, checkNextPort( false ){ };
				virtual ~UDPAddress()
				{
					SAFE_DELETE( userID );
				};

				char *userID;
				DWORD ip;
				WORD port;
				
				DWORD privateIP;
				WORD privatePort;

				WORD acceptPort;
				WORD managePort;

				DWORD gateWayIP;

				bool enableServerMode;

//				bool checkNextPort;

			};
			struct UDPAddressListRemoveIP
			{ 
				DWORD m_ip;
				WORD m_port;

				UDPAddressListRemoveIP (DWORD ip, WORD port ) : m_ip( ip ), m_port( port ){};
				bool operator()( const UDPAddress *info ) const 
				{
					if ( info )
					{
						if ( ( info->ip == m_ip ) && ( info->port == m_port ) )
							return ( true );
					}
					return ( false );
				} 
			};

			class UDPWorkerThread : public utillib::thread::Thread
			{
			public:
				UDPWorkerThread( );
				virtual ~UDPWorkerThread();

				DWORD run();

				void setUDPManager( UDPManager *manager ){ m_parentManager = manager;  };

			private:
				UDPManager *m_parentManager;
			};
		public:
			UDPManager();
			virtual ~UDPManager();
			
			int add( WORD port , bool manageMode = false );

			UDPManager::UDPAddress *insert( char *userID, DWORD gateWayIP, DWORD ip, WORD port , DWORD privateip, WORD privatePort , WORD acceptPort );
			UDPManager::UDPAddress *find( char *userID );
		
			bool sendManagerSocket( netlib::packet::Packet *packet, DWORD ip, WORD port )
			{
				if ( m_managerAcceptor ) return ( m_managerAcceptor->send( packet, ip, port ) );
				return ( false );
			};

			void run();
			void remove( char *userID );
			void remove( DWORD ip, WORD port );
			
			void setCheckPort( WORD firstPort, WORD secondPort );

			WORD getFirstCheckPort(){ return ( m_firstCheckPort ); };
			WORD getSecondCheckPort(){ return ( m_secondCheckPort ); };
			SocketManager *getSocketManager(){ return ( &m_socketManager ); };
		private:
			void remove();
			
			typedef std::set < UDPAcceptor * > UDPAcceptorList;
			UDPAcceptorList m_acceptorList;

			utillib::stl::MapWithString < UDPAddress * >  m_udpAddress;

			UDPAcceptor *m_managerAcceptor;

			WORD m_firstCheckPort;
			WORD m_secondCheckPort;

			SocketManager m_socketManager;
		};
	}
}

#endif